#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：transaction_record_management 
@File ：transaction.py
@IDE  ：PyCharm 
@Author ：李涵彬
@Date ：2024/3/31 21:12 
"""
import csv
import datetime
from typing import List


# 定义交易记录数据模型类
class Transaction:
	def __init__(self, id: int, date: datetime, symbol: str, amount: float, price: float, is_profit: bool):
		self.id = id
		self.date = date
		self.symbol = symbol
		self.amount = amount
		self.price = price
		self.is_profit = is_profit  # 标记这笔交易是盈利还是亏损


# 定义交易记录管理器类
class TransactionManager:
	def __init__(self, filename='transactions.csv'):
		"""
		初始化Transactions类的实例。
		:param filename: 存储交易数据的CSV文件名，默认为'transactions.csv'。
		"""
		self.transactions = []  # 初始化一个空列表，用于存储交易数据
		self.filename = filename  # 存储CSV文件名
		self.load_transactions_from_csv()  # 从CSV文件加载交易数据

	def load_transactions_from_csv(self):
		"""
		从CSV文件加载交易记录。
		此方法尝试打开指定的文件，读取每行数据并将其转换为交易对象。如果文件不存在，交易列表将为空。

		参数:
		self: 对象自身的引用。

		返回值:
		无返回值，但会将读取到的交易记录存储在对象的transactions属性中。
		"""
		try:
			# 尝试打开CSV文件并准备读取
			with open(self.filename, 'r', newline='') as file:
				reader = csv.reader(file)
				header = next(reader)  # 跳过CSV文件的标题行
				# 将每行CSV数据转换为交易对象，并存储在transactions属性中
				self.transactions = [self.csv_row_to_transaction(row) for row in reader]
		except FileNotFoundError:
			# 如果文件不存在，确保transactions属性为空列表
			self.transactions = []

	def save_transactions_to_csv(self):
		"""
		将交易数据保存到CSV文件中。

		该方法会打开指定的文件，将交易数据以CSV格式写入到文件中。每一行代表一笔交易，包含交易ID、日期、符号、数量和价格。

		参数:
		self: 对象自身的引用。
		"""
		with open(self.filename, 'w', newline='') as file:  # 以写入模式打开文件，并确保不会自动添加额外的空行
			writer = csv.writer(file)  # 创建一个CSV写入器
			writer.writerow(['ID', 'Date', 'Symbol', 'Quantity', 'Price'])  # 写入CSV文件的标题行
			for transaction in self.transactions:  # 遍历所有交易
				writer.writerow(self.transaction_to_csv_row(transaction))  # 将每笔交易转换为CSV行，并写入文件

	def csv_row_to_transaction(self, row):
		"""
		将CSV行数据转换为交易对象。

		参数:
		- self: 方法的对象引用。
		- row: 一个包含交易信息的行，顺序为交易ID、交易日期字符串、股票代码、交易数量、交易价格。

		返回值:
		- Transaction对象，包含交易的详细信息。
		"""
		# 从行中解构出交易信息的各个部分
		id_, date_str, symbol, quantity, price, is_profit = row
		# 将日期字符串转换为datetime对象
		date = datetime.datetime.strptime(date_str, '%Y-%m-%d')  # 假设日期格式为'YYYY-MM-DD'
		# 返回一个Transaction对象
		return Transaction(id_, date, symbol, float(quantity), float(price), is_profit)

	def transaction_to_csv_row(self, transaction):
		"""
		将交易信息转换为CSV行格式的列表。

		参数:
		- self: 方法的对象引用。
		- transaction: 一个具有id、date、symbol、quantity和price属性的交易对象。

		返回值:
		- 一个列表，包含交易的id、日期（格式为'YYYY-MM-DD'）、符号、数量和价格。
		"""
		return [transaction.id, transaction.date.strftime('%Y-%m-%d'), transaction.symbol, transaction.quantity,
				transaction.price]

	def add_transaction(self, transaction):
		"""
		将交易记录添加到列表中。

		参数:
		- self: 表示实例自身。
		- transaction: 表示要添加的交易记录。

		返回值:
		- 无
		"""
		self.transactions.append(transaction)  # 将指定的交易记录添加到交易列表中

	def modify_transaction(self, id, new_transaction):
		"""
		修改指定ID的交易记录

		:param id: 需要被修改的交易记录的ID
		:param new_transaction: 包含更新信息的新交易记录对象，其属性包括日期、符号、数量和价格
		:return: 无返回值
		"""
		# 遍历交易记录列表，查找需要修改的交易记录
		for t in self.transactions:
			if t.id == id:
				# 更新找到的交易记录的各项信息
				t.date = new_transaction.date
				t.symbol = new_transaction.symbol
				t.quantity = new_transaction.quantity
				t.price = new_transaction.price
				break

	def get_all_transactions(self):
		"""
		获取所有交易记录列表

		参数:
		self - 对象本身的引用

		返回值:
		返回一个包含所有交易记录的列表
		"""
		return self.transactions

	def filter_transactions_by_period(self, start_date: datetime, end_date: datetime) -> List[
		Transaction]:
		"""
		根据给定的开始和结束日期筛选交易记录。
		"""
		return [t for t in self.transactions if start_date <= t.date <= end_date]

	def get_weekly_transactions(self, reference_date: datetime) -> List[Transaction]:
		one_week_ago = reference_date - datetime.timedelta(days=7)
		return self.filter_transactions_by_period(one_week_ago, reference_date)

	def get_monthly_transactions(self, reference_date: datetime) -> List[Transaction]:
		one_month_ago = reference_date - datetime.timedelta(days=30)
		return self.filter_transactions_by_period(one_month_ago, reference_date)

	def get_half_yearly_transactions(self, reference_date: datetime) -> List[Transaction]:
		half_year_ago = reference_date - datetime.timedelta(days=180)
		return self.filter_transactions_by_period(half_year_ago, reference_date)

	def get_annual_transactions(self, reference_date: datetime) -> List[Transaction]:
		one_year_ago = reference_date - datetime.timedelta(days=365)
		return self.filter_transactions_by_period(one_year_ago, reference_date)

	def calculate_indicators(self, transactions: List[Transaction]) -> dict:
		"""
		计算交易指标。
		"""
		total_profit = 0
		total_loss = 0
		profit_count = 0
		loss_count = 0
		for t in transactions:
			pnl = t.amount * t.price
			if t.is_profit:
				total_profit += pnl
				profit_count += 1
			else:
				total_loss += pnl
				loss_count += 1

		avg_profit = total_profit / profit_count if profit_count > 0 else 0
		avg_loss = total_loss / loss_count if loss_count > 0 else 0
		win_rate = profit_count / (profit_count + loss_count) if profit_count + loss_count > 0 else 0
		profit_loss_ratio = total_profit / abs(total_loss) if total_loss != 0 else None

		indicators = {
			'total_profit': total_profit,
			'total_loss': total_loss,
			'profit_count': profit_count,
			'loss_count': loss_count,
			'average_profit': avg_profit,
			'average_loss': avg_loss,
			'win_rate': win_rate,
			'profit_loss_ratio': profit_loss_ratio,
		}

		return indicators


if __name__ == '__main__':
	# 假设我们已经有了一个实现了csv_row_to_transaction方法的TransactionManager类
	# 这个方法用于将CSV行数据转换为交易字典，为了简化此处未给出该方法的具体实现

	# 创建一个TransactionManager实例，假设CSV文件名是"transactions.csv"
	transaction_manager = TransactionManager()
	transaction_manager.filename = "./data/transactions.csv"

	# 假设我们有一个实际的CSV文件，内容如下：
	# Id, Date, Symbol, Amount, Price
	# 1, 2023 - 01 - 01, xauusd, 100.00, 2230.00
	# 2, 2023 - 01 - 02, btcusd, -50.00, 70000

	# 加载交易记录
	transaction_manager.load_transactions_from_csv()

	# 输出加载的交易记录以验证是否成功加载
	for transaction in transaction_manager.transactions:
		print(transaction.__dict__)

	# 此处预期输出应为两个交易记录（格式根据csv_row_to_transaction方法的实际转换逻辑而定）
	# 示例预期输出（假设csv_row_to_transaction直接返回字典）：
	# {'Date': '2023-01-01', 'Amount': '100.00', 'Description': 'Deposit'}
	# {'Date': '2023-01-02', 'Amount': '-50.00', 'Description': 'Withdrawal'}

	# 测试当文件不存在时的情况
	transaction_manager.filename = "nonexistent.csv"
	transaction_manager.load_transactions_from_csv()

	# 验证transactions属性是否为空列表
	assert transaction_manager.transactions == [], "When the CSV file doesn't exist, transactions should be an empty list."

	# 示例用法：
	manager = TransactionManager()
	# 加载交易记录
	manager.filename = "./data/transactions.csv"
	manager.load_transactions_from_csv()

	# 获取最近一周的交易记录
	weekly_transactions = manager.get_weekly_transactions(datetime.datetime.now())

	# 计算最近一周的交易指标
	weekly_indicators = manager.calculate_indicators(weekly_transactions)
	print(weekly_indicators)
